/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.testis.threading;

import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author nurhat
 */
public class TaskExecutor extends ThreadPoolExecutor {

    public ArrayList<TaskHolder> m_taskList =
            new ArrayList<TaskHolder>();
    private Runnable m_lastRunnable;

    public TaskExecutor(int poolSize,
            int maxPoolSize,
            int queueSize,
            long keepAliveTime) {
        super(poolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(queueSize));
        m_lastRunnable = null;
    }

    @Override
    protected synchronized void afterExecute(Runnable r,
            Throwable t) {
        super.afterExecute(r,
                t);
        if (r == m_lastRunnable) {
            m_lastRunnable = null;
        }
        clearFinishedTasks();

    }

    @Override
    protected synchronized void beforeExecute(Thread t,
            Runnable r) {
        super.beforeExecute(t,
                r);
        m_lastRunnable = r;
    }

    public synchronized void addTask(Task task) {
        Future<Task> future = (Future<Task>) super.submit(task);
        TaskHolder tsk = new TaskHolder(future,
                task);
        m_taskList.add(tsk);
        // System.out.println("Adding task:" +
        //                   task.getTaskId());
        //  printTasks();
    }

    public synchronized void cancelTask(String taskId) {
        TaskHolder taskHolder = findTask(taskId);
        if (taskHolder != null) {
            if (!taskHolder.getFuture().isDone()
                    && !taskHolder.getFuture().isCancelled()) {
                System.out.println("Cancelling task with id" + taskHolder.getTaskId());
                taskHolder.getTask().setCancelled(true);
                taskHolder.getFuture().cancel(true);
            }
            clearFinishedTasks();
        } else {
            System.out.println("Could not found task with id " + taskId);
        }
    }

    private TaskHolder findTask(String taskId) {
        TaskHolder taskHolder;
        String tmpTaskId;

        for (int i = 0; i < m_taskList.size(); i++) {
            taskHolder = m_taskList.get(i);
            tmpTaskId = taskHolder.getTaskId();

            if (tmpTaskId.equals(taskId)) {
                return taskHolder;
            }
        }
        return null;
    }

    public void abortAllTasks() {
        TaskHolder taskHolder;


        for (int i = 0; i < m_taskList.size(); i++) {
            taskHolder = m_taskList.get(i);
            cancelTask(taskHolder.getTaskId());
        }
        clearFinishedTasks();
    }

    private synchronized void clearFinishedTasks() {
        TaskHolder taskHolder;
        for (int i = 0; i < m_taskList.size(); i++) {
            taskHolder = m_taskList.get(i);
            if (taskHolder.getFuture().isCancelled()) {
                //   System.out.println("Removing cancelled task :" +
                //                      taskHolder.getTaskId());
                m_taskList.remove(taskHolder);
                taskHolder.getTask().setCancelled(true);
                taskHolder.afterExecute();
                this.remove(taskHolder.getTask());
            } else if (taskHolder.getFuture().isDone()) {
                //  System.out.println("Removing finished task:" +
                //                      taskHolder.getTaskId());
                taskHolder.getTask().setCancelled(false);
                m_taskList.remove(taskHolder);
                taskHolder.afterExecute();
                this.remove(taskHolder.getTask());
            }
        }
    }

    private synchronized void printTasks() {
        TaskHolder taskHolder;
        for (int i = 0; i < m_taskList.size(); i++) {
            taskHolder = m_taskList.get(i);
            System.out.println("Task with id " + taskHolder.getTaskId()
                    + " is in progress");
        }
    }

    /**
     * @return the m_lastRunnable
     */
    public synchronized Runnable getLastRunnable() {
        return m_lastRunnable;
    }
}
